package com.stu.execl.test.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @projectName: epic-kingdew
 * @packageName: com.chinamobile.epic.bobcats.util
 * @className: com.chinamobile.epic.bobcats.util-> ExcelUtils
 * @createDate: 2021-10-12 10:07
 * @author: ZhangSheng
 * @version: 1.0
 * @description:
 */
@Slf4j
public class ExcelUtils {

    /**
     * 获取文件流数据，封装成对应Class类型的List数据集
     * @param inputStream: excel数据流包装类
     * @param clazz: 转换的class对象
     * @return List<T>: <T>类型的数据集合
     */
    public static <T> List<T> getExcelDataList(InputStream inputStream, Class<T> clazz) throws IOException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        return getExcelDataList2(new XSSFWorkbook(inputStream), clazz);
    }

    /**
     *
     * @param exportData
     * @return：返回InputStream
     */
    public static InputStream getExcelFileStream(List<?> exportData){
        if (null == exportData || exportData.size() <= 0){
            return null;
        }
        Field[] declaredFields = exportData.get(0).getClass().getDeclaredFields();
        for (Field declaredField : declaredFields) {

        }
        return null;
    }


    public static <T> List<T> getExcelDataList2(XSSFWorkbook wb, Class<T> clazz) throws IOException,IllegalAccessException,InstantiationException,NoSuchMethodException,InvocationTargetException {
        List<T> objectList = new ArrayList<>();
        try {
            int numberOfSheets = wb.getNumberOfSheets();
            numberOfSheets = 1;
            for (int i = 0; i < numberOfSheets; i++) {
                XSSFSheet sheet = wb.getSheetAt(i);
                int firstRowNum = sheet.getFirstRowNum();
                int lastRowNum = sheet.getLastRowNum();
                if (firstRowNum == lastRowNum){
                    continue;
                }
                for(int j = firstRowNum + 1; j <= lastRowNum;j++){
                    XSSFRow row = sheet.getRow(j);
                    if (null == row){
                        break;
                    }
                    T obj = clazz.newInstance();
                    Map<Integer, Field> fileList = getFileList(obj);
                    int firstCellNum = row.getFirstCellNum();
                    int lastCellNum = row.getLastCellNum();
                    if (firstCellNum == lastCellNum){
                        continue;
                    }
                    for (int k = firstCellNum;k <= lastCellNum; k++){
                        XSSFCell cell = row.getCell(k);
                        if (cell == null){
                            continue;
                        }
                        int cellType = cell.getCellType();
                        if (cellType == 1){
                            String value = (null == cell.getStringCellValue() ||  "" == cell.getStringCellValue() ? "" : cell.getStringCellValue());
                            Field field = fileList.get(k);
                            if (null == field){
                                continue;
                            }
                            field.setAccessible(true);
                            obj.getClass().getMethod(getMethodName("set",field.getName()),String.class)
                                    .invoke(obj,value);
                        }else if(cellType == 0){
                            Double numericCellValue = cell.getNumericCellValue();
                            Field field = fileList.get(k);
                            field.setAccessible(true);
                            obj.getClass()
                                    .getMethod(getMethodName("set",field.getName()),String.class)
                                    .invoke(obj,null == numericCellValue ? 0 : String.valueOf(numericCellValue.intValue()));
                        }else {
                            continue;
                        }
                    }
                    objectList.add(obj);
                }
            }
        }finally {
            wb.close();
        }
        return objectList;
    }


    public static <T> List<T> getExcelDataList3(XSSFWorkbook wb, Class<T> clazz) throws IOException,IllegalAccessException,InstantiationException,NoSuchMethodException,InvocationTargetException {
        List<T> objectList = new ArrayList<>();
        try {
            XSSFSheet sheet = wb.getSheetAt(0);
            int firstRowNum = sheet.getFirstRowNum();
            int lastRowNum = sheet.getLastRowNum();
            if (firstRowNum == lastRowNum){
                log.info("该Sheet[{}]工作薄为空.",sheet.getSheetName());
                return objectList;
            }
            for(int j = firstRowNum + 1; j <= lastRowNum;j++){
                XSSFRow row = sheet.getRow(j);
                if (null == row){
                    break;
                }
                T obj = clazz.newInstance();
                Map<Integer, Field> fileList = getFileList(obj);
                int firstCellNum = row.getFirstCellNum();
                int lastCellNum = row.getLastCellNum();
                if (firstCellNum == lastCellNum){
                    continue;
                }
                for (int k = firstCellNum;k <= lastCellNum; k++){
                    XSSFCell cell = row.getCell(k);
                    if (cell == null){
                        continue;
                    }
                    int cellType = cell.getCellType();
                    if (cellType == 1){
                        String value = (StringUtils.hasText(cell.getStringCellValue()) ? "" : cell.getStringCellValue());
                        Field field = fileList.get(k);
                        field.setAccessible(true);
                        obj.getClass().getMethod(getMethodName("set",field.getName()),String.class)
                                .invoke(obj,value);
                    }else if(cellType == 0){
                        Double value = cell.getNumericCellValue();
                        String numericCellValue = new BigDecimal(String.valueOf(value.intValue())).stripTrailingZeros().toPlainString();
                        Field field = fileList.get(k);
                        field.setAccessible(true);
                        obj.getClass().getMethod(getMethodName("set",field.getName()),String.class)
                                .invoke(obj, numericCellValue);
                    }else {
                        log.info("导入数据类型不是字符串类型或者数字类型.");
                    }
                }
                objectList.add(obj);
            }
        }finally {
            wb.close();
        }
        return objectList;
    }

    private static Map<Integer,Field> getFileList(Object object)  {
        Map<Integer,Field> fieldMap  = new HashMap<>();
        Field[] declaredFields = object.getClass().getDeclaredFields();
        for (Field declaredField : declaredFields) {
            declaredField.setAccessible(true);
            Excel annotation = declaredField.getAnnotation(Excel.class);
            if(null != annotation){
                fieldMap.put(annotation.index(),declaredField);
            }
        }
        return fieldMap;
    }

    private static String  getMethodName(String pre,String targert){
        return new StringBuilder(pre).append(targert.substring(0,1).toUpperCase()).append(targert.substring(1)).toString();
    }

}
